using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using static System.Net.Mime.MediaTypeNames;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip;

namespace BardsTaleMapViewer {
  public class DungeonLevel {
    public static byte [] _dumpLEVS = ExtensionByte.CreateFromFile ("Files/B1 Atari/LEVS");
    public const int Width = 22;
    public const int Height = 22;

    public byte [] _dump;
    public int _dungeonIndexPlus1;
    public int _levelIndexPlus1;

    public int [,] _cellsInfo1;
    public int [,] _cellsInfo2;
    public int _difficulty;
    public int _isGoingUpLikeTower;
    public string _title;
    public List<Point> _specialsEventYX;
    public List<int> _specialsEventIndex;
    public List<int> _specialsEventParam;
    public List<Point> _specialsAntiMagicYX;
    public List<Point> _specialsTeleportYX;
    public List<Point> _specialsTeleportDestYX;
    public List<Point> _specialsSpinnerYX;
    public List<Point> _specialsSmokeYX;
    public List<Point> _specialsDrainHealthPointYX;
    public List<Point> _specialsRegenerateSpellPointYX;
    public List<Point> _specialsImmobilizeYX;
    public List<Point> _specialsTextYX;
    public List<Point> _specialsFightYX;
    public List<int> _specialsFightMonsterTypePlus1;
    public List<int> _specialsFightNb;
    public List<int> _specialsTextOffset;
    public List<int> _specialsTextIndex;
    public List<string> _specialsTextString;

    public Cell [,] _cells;

    public DungeonLevel (int dungeonIndexPlus1, int levelIndexPlus1) {
      _dungeonIndexPlus1 = dungeonIndexPlus1;
      _levelIndexPlus1 = levelIndexPlus1;

      int dungeonsToLevsIndex = 0x32E4A;
      int levsIndex = Game._dumpAtari.ReadByte (dungeonsToLevsIndex + _dungeonIndexPlus1);
      levsIndex += _levelIndexPlus1 - 1;

      int offset = (int) _dumpLEVS.ReadLong (levsIndex * 4);

      int offsetBufferTree = offset + 8;

      Huffman huffman = new Huffman (_dumpLEVS, ref offsetBufferTree, Computer.Atari);

      //huffman._currentMask = 0x80;
      //huffman._currentValue = dumpLEVS.ReadByte (ref offsetBufferTree);

      _dump = huffman.Decode_Atari (_dumpLEVS, ref offsetBufferTree, 2048);
      //Console.WriteLine (dump.Dump (0, 484, 0, 1, 22, false));

      Init ();
    }

    private void Init () {
      _cellsInfo1 = new int [Width, Height];
      _cellsInfo2 = new int [Width, Height];
      _cells = new Cell [Width, Height];
      for (int y = 0; y < 22; y++) {
        for (int x = 0; x < 22; x++) {
          int cellInfo1 = (int) _dump.ReadByte (0x000 + y * 22 + x);
          int cellInfo2 = (int) _dump.ReadByte (0x200 + y * 22 + x);
          _cellsInfo1 [x, y] = cellInfo1;
          _cellsInfo2 [x, y] = cellInfo2;
          _cells [x, y] = new Cell (this, x, y);
        }
      }


      int offset = 0x410;
      _difficulty = _dump.ReadByte (ref offset);
      offset = 0x415;
      _isGoingUpLikeTower = _dump.ReadByte (ref offset);

      // Title (0x416 10)
      _title = _dump.ReadStringTitle (0x416);
      offset += 10;

      _specialsEventYX = ReadCoordsYX (ref offset, 8); // 0x420

      // EventParams (0x430)
      List<Point> specialsEventParams = ReadCoordsYX (ref offset, 8);
      _specialsEventIndex = new List<int> ();
      _specialsEventParam = new List<int> ();
      foreach (Point param in specialsEventParams) {
        _specialsEventIndex.Add (param.Y);
        _specialsEventParam.Add (param.X);
      }
      if (_specialsEventYX.Count != _specialsEventIndex.Count)
        throw new Exception ();

      _specialsAntiMagicYX = ReadCoordsYX (ref offset, 16); // 0x440
      _specialsTeleportYX = ReadCoordsYX (ref offset, 8); // 0x460
      _specialsTeleportDestYX = ReadCoordsYX (ref offset, 8); // 0x470
      _specialsSpinnerYX = ReadCoordsYX (ref offset, 8); // 0x480
      _specialsSmokeYX = ReadCoordsYX (ref offset, 8); // 0x490
      _specialsDrainHealthPointYX = ReadCoordsYX (ref offset, 16); // 0x4A0
      _specialsRegenerateSpellPointYX = ReadCoordsYX (ref offset, 8); // 0x4C0
      _specialsImmobilizeYX = ReadCoordsYX (ref offset, 8); // 0x4D0
      _specialsTextYX = ReadCoordsYX (ref offset, 8); // 0x4E0
      _specialsFightYX = ReadCoordsYX (ref offset, 8); // 0x4F0

      // FightParams (0x500)
      List<Point> specialsFightParams = ReadCoordsYX (ref offset, 8);
      _specialsFightMonsterTypePlus1 = new List<int> ();
      _specialsFightNb = new List<int> ();
      foreach (Point param in specialsFightParams) {
        _specialsFightMonsterTypePlus1.Add (param.Y);
        _specialsFightNb.Add (param.X);
      }
      if (_specialsFightYX.Count != _specialsFightMonsterTypePlus1.Count)
        throw new Exception ();

      // TextOffset (0x510)
      List<Point> specialsTextOffsetLH = ReadCoordsYX (ref offset, 8);
      _specialsTextOffset = new List<int> ();
      int textIndex = 0;
      foreach (Point offsetLH in specialsTextOffsetLH) {
        int textOffset = ((offsetLH.X - 0xF8) << 8) + offsetLH.Y;
        if (textIndex < _specialsTextYX.Count)
          _specialsTextOffset.Add (textOffset);
        else {
          if (textOffset != 0x520)
            throw new Exception ();
        }
        textIndex++;
      }
      if (_specialsTextYX.Count != _specialsTextOffset.Count)
        throw new Exception ();

      // Texts (0x520)
      _specialsTextString = new List<string> ();
      foreach (int textOffset in _specialsTextOffset) {
        if (offset != textOffset)
          throw new Exception ();
        string text = _dump.ReadStringTitle (ref offset);
        //int i = textOffset + text.Length;
        _specialsTextString.Add (text);
      }

      // TextIndex
      _specialsTextIndex = new List<int> ();
      Dictionary<int, int> textOffsetsToIndex = new Dictionary<int, int> ();
      foreach (int textOffset in _specialsTextOffset) {
        if (!textOffsetsToIndex.ContainsKey (textOffset))
          textOffsetsToIndex.Add (textOffset, textOffsetsToIndex.Count + 1);
        _specialsTextIndex.Add (textOffsetsToIndex [textOffset]);
      }

      List<string> textsNotUsed = new List<string> ();
      while (offset < _dump.Length) {
        string textUnk = _dump.ReadStringTitle (ref offset);
        textsNotUsed.Add (textUnk);
      }

      // Check if several specials on the same cell
      Dictionary<Point, List<string>> cellsSpecials = new Dictionary<Point, List<string>> ();
      AddPoints (cellsSpecials, _specialsEventYX, "Event");
      AddPoints (cellsSpecials, _specialsAntiMagicYX, "AntiMagic");
      AddPoints (cellsSpecials, _specialsTeleportYX, "Teleport");
      AddPoints (cellsSpecials, _specialsSpinnerYX, "Spinner");
      AddPoints (cellsSpecials, _specialsSmokeYX, "Smoke");
      AddPoints (cellsSpecials, _specialsDrainHealthPointYX, "Drain");
      AddPoints (cellsSpecials, _specialsRegenerateSpellPointYX, "Regen");
      AddPoints (cellsSpecials, _specialsImmobilizeYX, "Immobilize");
      AddPoints (cellsSpecials, _specialsTextYX, "Text");
      AddPoints (cellsSpecials, _specialsFightYX, "Fight");

      foreach (KeyValuePair<Point, List<string>> kvp in cellsSpecials) {
        if (kvp.Value.Count > 1) {
          Console.Write ("{0} level {1} at ({2}, {3}) : Multiple specials : ", Dungeon.GetName (_dungeonIndexPlus1), _levelIndexPlus1, kvp.Key.X, kvp.Key.Y);
          foreach (string name in kvp.Value)
            Console.Write ("{0} ", name);
          Console.WriteLine ();
        }
      }

      // Check if a special is in a cell with a middle thing (monster, stairs, holes)
      CheckSpecialWithMiddle (_specialsEventYX, "Event");
      CheckSpecialWithMiddle (_specialsAntiMagicYX, "AntiMagic");
      CheckSpecialWithMiddle (_specialsTeleportYX, "Teleport");
      CheckSpecialWithMiddle (_specialsSpinnerYX, "Spinner");
      CheckSpecialWithMiddle (_specialsSmokeYX, "Smoke");
      CheckSpecialWithMiddle (_specialsDrainHealthPointYX, "DrainHealthPoint");
      CheckSpecialWithMiddle (_specialsRegenerateSpellPointYX, "RegenerateSpellPoint");
      CheckSpecialWithMiddle (_specialsImmobilizeYX, "Immobilize");
      CheckSpecialWithMiddle (_specialsTextYX, "Text");
      CheckSpecialWithMiddle (_specialsFightYX, "Fight");

      //// Check if a special anti magic ~ is in a cell with a middle thing (monster, stairs, holes)
      //foreach (Point coordXY in _specialsAntiMagicYX) {
      //  Cell cell = _cells [coordXY.X, coordXY.Y];
      //  if (cell.HasMonster || cell.HasStairsUp || cell.HasStairsDown || cell.HasHoleUp || cell.HasHoleDown)
      //    Console.WriteLine ("{0} level {1} at ({2}, {3}) : Special AntiMagic + ?", Dungeon.GetName (_dungeonIndexPlus1), _levelIndexPlus1, coordXY.X, coordXY.Y);
      //}

      //// Check if a special drain health point is in a cell with a middle thing (monster, stairs, holes)
      //foreach (Point coordXY in _specialsDrainHealthPointYX) {
      //  Cell cell = _cells [coordXY.X, coordXY.Y];
      //  if (cell.HasMonster || cell.HasStairsUp || cell.HasStairsDown || cell.HasHoleUp || cell.HasHoleDown)
      //    Console.WriteLine ("{0} level {1} at ({2}, {3}) : Special DrainHealthPoint + ?", Dungeon.GetName (_dungeonIndexPlus1), _levelIndexPlus1, coordXY.X, coordXY.Y);
      //}

      //// Check if a special regenerate spell point is in a cell with a middle thing (monster, stairs, holes)
      //foreach (Point coordXY in _specialsRegenerateSpellPointYX) {
      //  Cell cell = _cells [coordXY.X, coordXY.Y];
      //  if (cell.HasMonster || cell.HasStairsUp || cell.HasStairsDown || cell.HasHoleUp || cell.HasHoleDown)
      //    Console.WriteLine ("{0} level {1} at ({2}, {3}) : Special RegenerateSpellPoint + ?", Dungeon.GetName (_dungeonIndexPlus1), _levelIndexPlus1, coordXY.X, coordXY.Y);
      //}

      //Dump ();
    }

    private void CheckSpecialWithMiddle (List<Point> specialsYX, string name) {
      foreach (Point coordXY in specialsYX) {
        Cell cell = _cells [coordXY.X, coordXY.Y];
        if (cell.HasRandomMonster || cell.HasStairsUp || cell.HasStairsDown || cell.HasHoleUp || cell.HasHoleDown)
          Console.WriteLine ("{0} level {1} at ({2}, {3}) : Special {4} with{5}{6}{7}{8}{9}", Dungeon.GetName (_dungeonIndexPlus1), _levelIndexPlus1, coordXY.X, coordXY.Y, name,
            cell.HasRandomMonster ? " Monster" : "", cell.HasStairsUp ? " StairsUp" : "", cell.HasStairsDown ? " StairsDown" : "", cell.HasHoleUp ? " HoleUp" : "", cell.HasHoleDown ? " HoleDown" : "");
      }
    }

    private bool HasRandomMonsters {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.HasRandomMonster)
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasTraps {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.HasTrap)
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasDarkness {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.HasDarkness)
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasStairsDown {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.HasStairsDown)
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasDoorsNormal {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.IsNormalDoor (Cell.Direction.North) || cell.IsNormalDoor (Cell.Direction.South) || cell.IsNormalDoor (Cell.Direction.East) || cell.IsNormalDoor (Cell.Direction.West))
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasDoorsNormalOneWay {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            int x = cellX;
            int y = Height - 1 - cellY;
            Cell cell = _cells [x, y];
            Cell cellWest = _cells [(x + Width - 1) % Width, y];
            Cell cellEast = _cells [(x + Width + 1) % Width, y];
            Cell cellNorth = _cells [x, (y + Height + 1) % Height];
            Cell cellSouth = _cells [x, (y + Height - 1) % Height];
            bool found = false;
            if (cell.IsNormalDoor (Cell.Direction.West) && cellWest.IsWall (Cell.Direction.East))
              found = true;
            if (cell.IsNormalDoor (Cell.Direction.East) && cellEast.IsWall (Cell.Direction.West))
              found = true;
            if (cell.IsNormalDoor (Cell.Direction.North) && cellNorth.IsWall (Cell.Direction.South))
              found = true;
            if (cell.IsNormalDoor (Cell.Direction.South) && cellSouth.IsWall (Cell.Direction.North))
              found = true;
            if (found) {
              return (true);
            }
          }
        }
        return (false);
      }
    }


    private bool HasDoorsHiddenOneWay {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            int x = cellX;
            int y = Height - 1 - cellY;
            Cell cell = _cells [x, y];
            Cell cellWest = _cells [(x + Width - 1) % Width, y];
            Cell cellEast = _cells [(x + Width + 1) % Width, y];
            Cell cellNorth = _cells [x, (y + Height + 1) % Height];
            Cell cellSouth = _cells [x, (y + Height - 1) % Height];
            bool found = false;
            if (cell.IsHiddenDoor (Cell.Direction.West) && cellWest.IsWall (Cell.Direction.East))
              found = true;
            if (cell.IsHiddenDoor (Cell.Direction.East) && cellEast.IsWall (Cell.Direction.West))
              found = true;
            if (cell.IsHiddenDoor (Cell.Direction.North) && cellNorth.IsWall (Cell.Direction.South))
              found = true;
            if (cell.IsHiddenDoor (Cell.Direction.South) && cellSouth.IsWall (Cell.Direction.North))
              found = true;
            if (found) {
              return (true);
            }
          }
        }
        return (false);
      }
    }

    private bool HasDoorsHidden {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.IsHiddenDoor (Cell.Direction.North) || cell.IsHiddenDoor (Cell.Direction.South) || cell.IsHiddenDoor (Cell.Direction.East) || cell.IsHiddenDoor (Cell.Direction.West))
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasStairsUp {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.HasStairsUp)
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasHolesDown {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.HasHoleDown)
              return (true);
          }
        }
        return (false);
      }
    }

    private bool HasHolesUp {
      get {
        for (int cellY = 0; cellY < Height; cellY++) {
          for (int cellX = 0; cellX < Width; cellX++) {
            Cell cell = _cells [cellX, Height - 1 - cellY];
            if (cell.HasHoleUp)
              return (true);
          }
        }
        return (false);
      }
    }

    private void AddPoints (Dictionary<Point, List<string>> cellsSpecials, List<Point> coordsXY, string name) {
      foreach (Point coordXY in coordsXY) {
        if (!cellsSpecials.ContainsKey (coordXY))
          cellsSpecials.Add (coordXY, new List<string> ());
        cellsSpecials [coordXY].Add (name);
      }
    }

    private List<Point> ReadCoordsYX (ref int offset, int size) {
      List<Point> coordsYX = new List<Point> ();
      for (int i = 0; i < size; i++) {
        int y = _dump.ReadByte (ref offset);
        int x = _dump.ReadByte (ref offset);
        if ((y != 0xFF) || (x != 0xFF))
          coordsYX.Add (new Point (x, y));
      }
      return (coordsYX);
    }

    public void Draw (Graphics g, int x, int y, int cellSize, Beastiary beastiary) {
      g.FillRectangle (Brushes.Red, x + cellSize, y + cellSize, Width * cellSize + 2, Height * cellSize + 2);

      // Top
      for (int i = 0; i < Width; i++) {
        Game._bitmapFont.DrawText (g, x + 1 + (i + 1) * cellSize + cellSize / 2,
                                      y + 1 + cellSize / 2, i.ToString (), Color.White, AlignementH.Center, AlignementV.Center, false);
        g.FillRectangle (Brushes.Red, x + 1 + (i + 1) * cellSize,
                                      y + 1 + cellSize - cellSize / 2, 1, cellSize / 2);
        g.FillRectangle (Brushes.Red, x + 1 + (i + 1) * cellSize + cellSize - 1,
                                      y + 1 + cellSize - cellSize / 2, 1, cellSize / 2);
      }

      // Bottom
      for (int i = 0; i < Width; i++) {
        Game._bitmapFont.DrawText (g, x + 1 + (i + 1) * cellSize + cellSize / 2,
                                      y + 1 + cellSize / 2 + Height * (cellSize + 1), i.ToString (), Color.White, AlignementH.Center, AlignementV.Center, false);
        g.FillRectangle (Brushes.Red, x + 1 + (i + 1) * cellSize,
                                      y + 1 + Height * (cellSize + 1), 1, cellSize / 2);
        g.FillRectangle (Brushes.Red, x + 1 + (i + 1) * cellSize + cellSize - 1,
                                      y + 1 + Height * (cellSize + 1), 1, cellSize / 2);
      }

      // Left
      for (int i = 0; i < Height; i++) {
        Game._bitmapFont.DrawText (g, x + 1 + cellSize / 2,
                                      y + 1 + (i + 1) * cellSize + cellSize / 2, (Height - 1 - i).ToString (), Color.White, AlignementH.Center, AlignementV.Center, false);
        g.FillRectangle (Brushes.Red, x + 1 + cellSize - cellSize / 2,
                                      y + 1 + (i + 1) * cellSize, cellSize / 2, 1);
        g.FillRectangle (Brushes.Red, x + 1 + cellSize - cellSize / 2,
                                      y + 1 + (i + 1) * cellSize + cellSize - 1, cellSize / 2, 1);
      }

      // Right
      for (int i = 0; i < Height; i++) {
        Game._bitmapFont.DrawText (g, x + 1 + cellSize / 2 + Width * (cellSize + 1),
                                      y + 1 + (i + 1) * cellSize + cellSize / 2, (Height - 1 - i).ToString (), Color.White, AlignementH.Center, AlignementV.Center, false);
        g.FillRectangle (Brushes.Red, x + 1 + Width * (cellSize + 1),
                                      y + 1 + (i + 1) * cellSize, cellSize / 2, 1);
        g.FillRectangle (Brushes.Red, x + 1 + Width * (cellSize + 1),
                                      y + 1 + (i + 1) * cellSize + cellSize - 1, cellSize / 2, 1);
      }

      DrawCells (g, x + 1 + cellSize, y + 1 + cellSize, cellSize);
      //DrawSpecialText (g, xOrigin + 1 + cellSize, yOrigin + 1 + cellSize, cellSize);
      //DrawSpecialFight (g, xOrigin + 1 + cellSize, yOrigin + 1 + cellSize, cellSize);
      DrawLegend (g, x + 1 + cellSize + Width * cellSize + cellSize + cellSize / 2, y + 1 + 0, cellSize, false, beastiary);
      //DrawSpecialTexts (g, x + 1 + cellSize, y + 1 + cellSize + Height * cellSize + cellSize + cellSize / 2);
      //DrawSpecialTexts (g, x + 1 + cellSize + Width * cellSize + cellSize + cellSize / 2 + 200, y + 1 + cellSize);
    }

    private void DrawCells (Graphics g, int x, int y, int cellSize) {
      for (int cellY = 0; cellY < Height; cellY++) {
        for (int cellX = 0; cellX < Width; cellX++) {
          Cell cell = _cells [cellX, Height - 1 - cellY];
          cell.DrawLayer1 (g, x + cellX * cellSize, y + cellY * cellSize, cellSize);
        }
      }

      for (int cellY = 0; cellY < Height; cellY++) {
        for (int cellX = 0; cellX < Width; cellX++) {
          Cell cell = _cells [cellX, Height - 1 - cellY];
          cell.DrawLayer2 (g, x + cellX * cellSize, y + cellY * cellSize, cellSize);
        }
      }

      for (int cellY = 0; cellY < Height; cellY++) {
        for (int cellX = 0; cellX < Width; cellX++) {
          Cell cell = _cells [cellX, Height - 1 - cellY];
          cell.DrawLayer3 (g, x + cellX * cellSize, y + cellY * cellSize, cellSize);
        }
      }
    }

    private void DrawLegend (Graphics g, int x, int y, int cellSize, bool forceFull, Beastiary beastiary) {
      int interleave = cellSize + 2;

      Game._bitmapFont.DrawText (g, x, y + cellSize / 2, string.Format ("Difficulty: {0}", _difficulty), Color.White, AlignementH.Left, AlignementV.Center, false);
      y += Game._bitmapFont._glyphHeight;
      Game._bitmapFont.DrawText (g, x, y + cellSize / 2, string.Format ("  Gold per kill: [0;{0}]", beastiary._difficultiesGoldPerKillMask [_difficulty]), Color.White, AlignementH.Left, AlignementV.Center, false);
      y += interleave;

      if ((_specialsTextYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialText_ (g, x, y, cellSize, "x");
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Text x", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      //int interleave = cellSize + Cell._wallThickness;
      if ((_specialsEventYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialEvent_ (g, x, y, cellSize, "x");
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Event x", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsFightYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialFight_ (g, x, y, cellSize, "x", null);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Monster x", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasRandomMonsters || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawRandomMonster (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Random monster", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasTraps || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawTrap (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Trap", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasDarkness || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawDarkness (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Darkness", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsAntiMagicYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialAntiMagic_ (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Anti Magic area", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsTeleportYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawFloor (g, x + cellSize, y, cellSize, false, false);
        Cell.DrawFloor (g, x + cellSize * 2, y, cellSize, false, false);
        Cell.DrawSpecialTeleport_ (g, x, y, cellSize, new Point (0, 0), new Point (2, 0));
        Game._bitmapFont.DrawText (g, x + cellSize * 3 + cellSize / 2, y + cellSize / 2, "Teleporter", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsSpinnerYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialSpinner_ (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Spinner", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsSmokeYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialSmoke_ (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Smoke area", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsDrainHealthPointYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialDrainHealthPoint_ (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "HP drain area", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsRegenerateSpellPointYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialRegenerateSpellPoint_ (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "SP restore area", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if ((_specialsImmobilizeYX.Count > 0) || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, true, false);
        Cell.DrawSpecialImmobilize_ (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Party paralysis", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasDoorsNormal || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawFloor (g, x + cellSize, y, cellSize, false, false);
        Cell.DrawWall (g, x, y, cellSize, Cell.Direction.East);
        Cell.DrawWall (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Cell.DrawDoorNormal (g, x, y, cellSize, Cell.Direction.East);
        Cell.DrawDoorNormal (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Game._bitmapFont.DrawText (g, x + cellSize * 2 + cellSize / 2, y + cellSize / 2, "Door", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasDoorsNormalOneWay || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawFloor (g, x + cellSize, y, cellSize, false, false);
        Cell.DrawWall (g, x, y, cellSize, Cell.Direction.East);
        Cell.DrawWall (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Cell.DrawDoorNormal (g, x, y, cellSize, Cell.Direction.East);
        //Cell.DrawDoorNormal (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Game._bitmapFont.DrawText (g, x + cellSize * 2 + cellSize / 2, y + cellSize / 2, "One-way door", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasDoorsHidden || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawFloor (g, x + cellSize, y, cellSize, false, false);
        Cell.DrawWall (g, x, y, cellSize, Cell.Direction.East);
        Cell.DrawWall (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Cell.DrawDoorHidden (g, x, y, cellSize, Cell.Direction.East);
        Cell.DrawDoorHidden (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Game._bitmapFont.DrawText (g, x + cellSize * 2 + cellSize / 2, y + cellSize / 2, "Hidden door", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasDoorsHiddenOneWay || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawFloor (g, x + cellSize, y, cellSize, false, false);
        Cell.DrawWall (g, x, y, cellSize, Cell.Direction.East);
        Cell.DrawWall (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Cell.DrawDoorHidden (g, x, y, cellSize, Cell.Direction.East);
        //Cell.DrawDoorHidden (g, x + cellSize, y, cellSize, Cell.Direction.West);
        Game._bitmapFont.DrawText (g, x + cellSize * 2 + cellSize / 2, y + cellSize / 2, "One-way hidden door", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasStairsUp || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawStairsUp (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Stairs up", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasStairsDown || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawStairsDown (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Stairs down", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasHolesUp || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawHoleUp (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Hole up", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }

      if (HasHolesDown || forceFull) {
        Cell.DrawFloor (g, x, y, cellSize, false, false);
        Cell.DrawHoleDown (g, x, y, cellSize);
        Game._bitmapFont.DrawText (g, x + cellSize + cellSize / 2, y + cellSize / 2, "Hole down", Color.White, AlignementH.Left, AlignementV.Center, false);
        y += interleave;
      }
    }

    public string BuildTexts () {
      StringBuilder sb = new StringBuilder ();
      for (int i = 0; i < _specialsTextString.Count; i++) {
        string text = _specialsTextString [i];
        string text2 = text.Replace ("\0", Environment.NewLine);
        sb.AppendLine (string.Format ("Text {0}:", i));
        sb.AppendLine (text2);
        sb.AppendLine ();
      }
      return (sb.ToString ());
    }

    public string BuildMonsters (Beastiary beastiary) {
      StringBuilder sb = new StringBuilder ();
      for (int i = 0; i < _specialsFightMonsterTypePlus1.Count; i++) {
        int monsterTypePlus1 = _specialsFightMonsterTypePlus1 [i];
        int nb = _specialsFightNb [i];
        MonsterType monsterType = beastiary._monsterTypes [monsterTypePlus1 - 1];
        sb.AppendLine (string.Format ("M{0}: {1} {2} ({3}) ", i, nb, monsterType.GetName (nb), monsterType.Text));
      }
      return (sb.ToString ());
    }

    public string BuildEvents () {
      StringBuilder sb = new StringBuilder ();
      for (int i = 0; i < _specialsEventIndex.Count; i++) {
        int eventIndex = _specialsEventIndex [i];
        int eventParam = _specialsEventParam [i];
        sb.AppendLine (string.Format ("E{0}: {1}", i, BuildEvent (eventIndex, eventParam)));
      }
      return (sb.ToString ());
    }

    public string BuildEvent (int eventIndex, int eventParam) {
      StringBuilder sb = new StringBuilder ();
      sb.AppendFormat ("#{0} ", eventIndex);
      if (eventIndex == 10) {
        sb.AppendLineFormat ("Trap");
      }
      else if (eventIndex == 16) {
        sb.AppendLineFormat ("There are stairs here, which seem to go a long way up. Do you wish to take them?");
        sb.AppendLineFormat ("Teleport: City 1/28");
      }
      else if (eventIndex == 17) {
        sb.AppendLineFormat ("Statue: Spidergod: Search/Exit");
        sb.AppendLineFormat ("Search: Fight: Spinner");
      }
      else if (eventIndex == 18)
        sb.AppendLineFormat ("Light beam: Try Crossing/Exit");
      else if (eventIndex == 19) {
        sb.AppendLineFormat ("Mouth: A magic mouth on the wall speaks: \"Know this, that a man called Tarjan, thought to many to be insane, had through wizardly powers");
        sb.AppendLineFormat ("...proclaimed himself a god in Skara Brae a hundred years ago. His image is locked in stone until made whole again...\"");
      }
      else if (eventIndex == 20) {
        sb.AppendLineFormat ("Bashar Kavilor");
        sb.AppendLineFormat ("You have entered the living chambers of Bashar Kavilor, the High Priest. ");
        sb.AppendLineFormat ("He screams, \"Infidel! Face now the wrath of a servant of the Mad One!\"");
        sb.AppendLineFormat ("I think you're in trouble.");
        sb.AppendLineFormat ("Fight: Master sorcerer");
      }
      else if (eventIndex == 21) {
        sb.AppendLineFormat ("This is the High Priest's treasure chamber. His pet dragon, Sphynx, peers at you hungrily. \"Sphynx eat now, \" it growls.");
        sb.AppendLineFormat ("Fight: Grey dragon");
      }
      else if (eventIndex == 22) {
        sb.AppendLineFormat ("Witch King");
        sb.AppendLineFormat ("Before you lies the ancient burial chamber of King Aildrek, now a creature ");
        sb.AppendLineFormat ("of darkness. \"Now, mortal man, I will drink of your souls,\" he hisses.");
        sb.AppendLineFormat ("Fight: Spectre");
        sb.AppendLineFormat ("Treasure: Eye");
      }
      else if (eventIndex == 24) {
        sb.AppendLineFormat ("Throne");
        sb.AppendLineFormat ("You are at the Baron's throne. Who wishes to sit on it?");
        sb.AppendLineFormat ("Hobbit: The sound of grating stone is heard.");
      }
      else if (eventIndex == 25) {
        sb.AppendLineFormat ("Guard Captain");
        sb.AppendLineFormat ("You see the Captain of the Guard standing before you.\"Die, scum!\" he screams as he runs insanely toward you.");
        sb.AppendLineFormat ("Fight: Master ninja");
      }
      else if (eventIndex == 26) {
        sb.AppendLineFormat ("Robed Men");
        sb.AppendLineFormat ("Before you stand six warriors, dressed in bright green robes. \"Intruders!\"");
        sb.AppendLineFormat ("They scream battle cries as they run toward you with drawn swords.");
        sb.AppendLineFormat ("Fight: 6 Berserkers");
        sb.AppendLineFormat ("Treasure: Robes");
      }
      else if (eventIndex == 27)
        sb.AppendLineFormat ("Treasure: Crystal Sword");
      else if (eventIndex == 28) {
        sb.AppendLineFormat ("Old man");
        sb.AppendLineFormat ("A wizened man appears before you, saying, \"Answer this riddle to pass: \"");
        sb.AppendLineFormat ("\"Once man alive");
        sb.AppendLineFormat ("Now living death");
        sb.AppendLineFormat ("It drinketh blood");
        sb.AppendLineFormat ("N' stealeth breath.\"");
        sb.AppendLineFormat ("Will you: Answer riddle/Fight him/Exit");
        sb.AppendLineFormat ("Answer: VAMPIRE: \"Pass at your leisure, \" the Master Sorcerer says.");
        sb.AppendLineFormat ("Fight: Master sorcerer");
      }
      else if (eventIndex == 29)
        sb.AppendLineFormat ("Treasure: Silver Square");
      else if (eventIndex == 30) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this riddle:");
        sb.AppendLineFormat ("Past warscapes fought by men long dead, and treasures lost on bloodied fields,");
        sb.AppendLineFormat ("the One God lifts his thorn-crowned head, and lays a strength on friendly..");
        sb.AppendLineFormat ("Answer: SHIELDS");
        sb.AppendLineFormat ("Treasure: Ybarrashield");
      }
      else if (eventIndex == 31) {
        sb.AppendLineFormat ("Robed Men");
        sb.AppendLineFormat ("The legions of Baron Harkyn stand before you, recognizing you as intruders, \"Death to them!\" they scream.");
        sb.AppendLineFormat ("If not owning Robes: Fight: 4 groups of 99 Berserkers");
      }
      else if (eventIndex == 32) {
        sb.AppendLineFormat ("Old statue");
        sb.AppendLineFormat ("An old statue of a fifteen foot tall warrior stands before you.");
        sb.AppendLineFormat ("Will you: Approach it/Exit");
        sb.AppendLineFormat ("If not owning Eye: It appears harmless.");
        sb.AppendLineFormat ("If owning Eye: An Eye levitates from X and goes into the statue's empty socket. The statue comes to life!");
        sb.AppendLineFormat ("Fight: Mad God");
        sb.AppendLineFormat ("Teleport: City 28/2");
      }
      else if (eventIndex == 33) {
        sb.AppendLineFormat ("An old man");
        sb.AppendLineFormat ("An old man stands before you saying, \"Answer this question to pass:");
        sb.AppendLineFormat ("What tavern lies off Night Archer street?\"");
        sb.AppendLineFormat ("Will you: Answer question/Fight him/Exit");
        sb.AppendLineFormat ("Fight: Old man/4 lesser demons");
        sb.AppendLineFormat ("Answer: SKULL/SKULL TAVERN: \"Pass, oh learned ones, \" he says.");
      }
      else if (eventIndex == 37) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"Name the one of cold, foretold twofold: \"");
        sb.AppendLineFormat ("Answer: STONE GOLEM");
      }
      else if (eventIndex == 38) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"Name the endless byway and your path shall be guaranteed: \"");
        sb.AppendLineFormat ("Answer: SINISTER");
      }
      else if (eventIndex == 39) {
        sb.AppendLineFormat ("Treasure: Silver Triangle");
      }
      else if (eventIndex == 40) {
        sb.AppendLineFormat ("Golem!");
        sb.AppendLineFormat ("A crystal statue comes to life before you, ready to attack!");
        sb.AppendLineFormat ("Will you: Fight it/Exit");
        sb.AppendLineFormat ("Fight: Crystal Golem");
        sb.AppendLineFormat ("If not equipping Crystal Sword: Crystal Golem respawn");
      }
      else if (eventIndex == 41) {
        sb.AppendLineFormat ("If not owning Onyx Key");
        sb.AppendLineFormat ("Kylearan");
        sb.AppendLineFormat ("Greetings! I am Kylearan, oh perseverent ones, the good wizard of Skara Brae. Put away your weapons, for I am your ally, not an enemy.");
        sb.AppendLineFormat ("You have passed my tests, and can now continue on to your true quest, the source of evil in Skara Brae -- Mangar the Dark, my nemesis.");
        sb.AppendLineFormat ("Mangar's tower, at the opposite corner of Skara Brae, is a five level deathtrap, which can only be entered by use of an onyx key.");
        sb.AppendLineFormat ("Good luck, and remember, seeing is not always believing.");
        sb.AppendLineFormat ("Treasure: Onyx Key");
      }
      else if (eventIndex == 43) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"Perseverence in all things.\"");
      }
      else if (eventIndex == 44) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"Two shapes yours, one's around; Speak the shape and final found\"");
        sb.AppendLineFormat ("Answer: CIRCLE");
        sb.AppendLineFormat ("Treasure: Silver Circle");
      }
      else if (eventIndex == 45) {
        sb.AppendLineFormat ("Keymaster");
        sb.AppendLineFormat ("An old man is here, and says to you:");
        sb.AppendLineFormat ("\"I am the Keymaster.I have something to sell you for the low price of 50000 gold pieces.\"");
        sb.AppendLineFormat ("Will you: Buy item/Fight him/Exit");
        sb.AppendLineFormat ("Buy: Master Key");
        sb.AppendLineFormat ("Fight: 1 Old man / 6 Wraiths");
      }
      else if (eventIndex == 46) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"Speak the seven of the One God, in Sequence, and seek the lost stairs: \"");
        sb.AppendLineFormat ("Answer: LIE/WITH/PASSION/AND/BE/FOREVER/DAMNED");
      }
      else if (eventIndex == 47) {
        sb.AppendLineFormat ("There is a large black coffin in this tomb.");
        sb.AppendLineFormat ("Do you wish to: Open it/Exit");
        sb.AppendLineFormat ("Open: A Vampire Lord rises from the coffin. He seems rather disturbed.");
        sb.AppendLineFormat ("Fight: Vampire lord");
      }
      else if (eventIndex == 48) {
        sb.AppendLineFormat ("If playing music: Your music caused two sleeping dragons to continue slumbering.");
        sb.AppendLineFormat ("If not playing music: Two sleeping dragons awaken at your passage. \"Hmm, humans for dinner again, Gor,\" says the small one. \"Why don't we get any pork up here?\"");
        sb.AppendLineFormat ("Fight: 2 Red dragons");
      }
      else if (eventIndex == 49) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"Name the greatest son of Odin and win his aid.\"");
        sb.AppendLineFormat ("Answer: THOR");
        sb.AppendLineFormat ("Treasure: Thor Figurine");
      }
      else if (eventIndex == 50) {
        sb.AppendLineFormat ("Dungeon_EventFunction50_set1");
      }
      else if (eventIndex == 51) {
        sb.AppendLineFormat ("On the wall to the north are etched 3 geometric shapes: a square, a circle, and a triangle.");
      }
      else if (eventIndex == 52) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"What can bind the mightiest foes ?\"");
        sb.AppendLineFormat ("Answer: SPECTRE SNARE");
        sb.AppendLineFormat ("Treasure: Spectre Snare");
      }
      else if (eventIndex == 53) {
        sb.AppendLineFormat ("Nothing ?");
      }
      else if (eventIndex == 54) {
        sb.AppendLineFormat ("There is a pool of boiling liquid here.");
        sb.AppendLineFormat ("Will you: Dive in/Exit");
        sb.AppendLineFormat ("Teleport: 10/6");
      }
      else if (eventIndex == 55) {
        sb.AppendLineFormat ("This is Mangar's treasure trove. Two dragons are here, and they're very hungry. I think you're in some real trouble.");
        sb.AppendLineFormat ("Fight: 2 Black dragons");
      }
      else if (eventIndex == 56) {
        sb.AppendLineFormat ("Mouth...");
        sb.AppendLineFormat ("A magic mouth on the wall speaks to you, saying this:");
        sb.AppendLineFormat ("\"Death to those who would attack the mighty one!\"");
      }
      else if (eventIndex == 57) {
        sb.AppendLineFormat ("POSSESS a random front member");
      }
      else if (eventIndex == 58) {
        sb.AppendLineFormat ("Mangar!");
        sb.AppendLineFormat ("You stand in the antechamber of Mangar the Dark, evil Archmage of Skara Brae.");
        sb.AppendLineFormat ("Mangar glares at you with deep hatred. \"Die, mortals!\" he screams.");
        sb.AppendLineFormat ("With a wave of his hand a few of his close friends drop by. They don't look like a fun group.");
        sb.AppendLineFormat ("Fight: 2 Demon lords/3 Vampire lords/Mangar");
        sb.AppendLineFormat ("If won: Kylearan");
        sb.AppendLineFormat ("Kylearan, the good Archmage, appears before you in a flash of light.");
        sb.AppendLineFormat ("\"Well done!\" he cries, beaming. \"Your quest in Skara Brae is now finished!\"");
        sb.AppendLineFormat ("\"The evil one is now defeated, and his spell of winter will soon end.\"");
        sb.AppendLineFormat ("\"You will all, as a symbol of my gratitude, receive a gold and experience bonus of 300,000 units. Fare well and live long!\"");
      }
      else {
        throw new Exception ();
        sb.AppendLineFormat ("({0}) TODO", eventParam);
      }
      return (sb.ToString ());
    }

    public void DrawSpecialTexts (Graphics g, int x, int y) {
      for (int i = 0; i < _specialsTextString.Count; i++) {
        int height = DrawSpecialText (g, x, y, i);
        y += height + Game._bitmapFontSmall._glyphHeight;
      }
    }

    public int DrawSpecialText (Graphics g, int x, int y, int index) {
      string text = _specialsTextString [index];
      int x2 = x;
      int y2 = y;

      Game._bitmapFontSmall.DrawText (g, x2, y2, string.Format ("Text {0}:", index), Color.White, AlignementH.Left, AlignementV.Top, false);
      y2 += Game._bitmapFontSmall._glyphHeight;
      foreach (char c in text) {
        if (c == '\0') {
          x2 = x;
          y2 += Game._bitmapFontSmall._glyphHeight;
        }
        else {
          Game._bitmapFontSmall.DrawText (g, x2, y2, c.ToString (), Color.White, AlignementH.Left, AlignementV.Top, false);
          x2 += Game._bitmapFontSmall._glyphWidth;
        }
      }
      return (y2 - y + Game._bitmapFontSmall._glyphHeight);
    }

    //private void DrawSpecialText (Graphics g, int xOrigin, int yOrigin, int cellSize) {
    //  for (int i = 0; i < _specialsTextYX.Count; i++) {
    //    Point coordXY = _specialsTextYX [i];
    //    int x = xOrigin + coordXY.X * cellSize;
    //    int y = yOrigin + (Height - 1 - coordXY.Y) * cellSize;
    //    int textIndex = _specialsTextIndex [i];
    //    Game._bitmapFontSmall.DrawText (g, x + cellSize / 2, y + cellSize - Cell._wallThickness, string.Format ("T{0}", textIndex), Color.Black, AlignementH.Center, AlignementV.Bottom, Color.White);
    //  }
    //}

    //private void DrawSpecialFight (Graphics g, int xOrigin, int yOrigin, int cellSize) {
    //  for (int i = 0; i < _specialsFightYX.Count; i++) {
    //    Point coordXY = _specialsFightYX [i];
    //    int x = xOrigin + coordXY.X * cellSize;
    //    int y = yOrigin + (Height - 1 - coordXY.Y) * cellSize;
    //    int monsterTypePlus1 = _specialsFightMonsterTypePlus1 [i];
    //    int nb = _specialsFightNb [i];
    //    Game._bitmapFontSmall.DrawText (g, x + cellSize / 2, y + cellSize / 2, string.Format ("M{0}", monsterTypePlus1), Color.Red, AlignementH.Center, AlignementV.Center, Color.White);
    //  }
    //}

    private void Dump () {
      for (int y = Height; y >= 0; y--) {
        for (int x = 0; x < Width; x++) {
          Console.Write (string.Format ("{0:X2} ", _cellsInfo1 [x, y]));
        }
        Console.WriteLine ();
      }
    }
  }
}
